/*
* mkl_lapack.cpp
* 
* Copyright (c) 2003-2004, .NET Analytics Project. All rights reserved.
*/
#ifdef _WINDOWS
	#ifndef VC_EXTRALEAN
		#define VC_EXTRALEAN
	#endif
	#include "windows.h"
#endif
#include <algorithm>
#include "mkl_cblas.h"
#include "mkl_lapack.h"

#ifdef _WINDOWS
	#define DLLEXPORT __declspec( dllexport )
#else
	#define DLLEXPORT
#endif
using namespace std;

extern "C" {
	inline char getTchar(const CBLAS_TRANSPOSE trans){
		char cTrans;
		switch( trans ){
			case  CblasNoTrans : cTrans = 'N';
				break;
			case  CblasTrans : cTrans = 'T';
				break;
			case  CblasConjTrans : cTrans = 'C';
				break;
		}
		return cTrans;
	}

	inline char getSchar(const CBLAS_SIDE side){
		char cSide;
		switch( side ){
			case  CblasLeft : cSide= 'L';
				break;
			case  CblasRight : cSide = 'R';
				break;
		}
		return cSide;
	}

    inline char getUchar(const CBLAS_UPLO uplo){
        char cUplo;
        switch( uplo ){
            case CblasLower : cUplo = 'L';
                break;
            case CblasUpper : cUplo = 'U';
                break;
        }
        return cUplo;
    }


	int DLLEXPORT dna_lapack_sormbr( int block_size, char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, float* a, int lda, float* tau, float* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		float* work = new float[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		sormbr(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dormbr( int block_size, char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, double* a, int lda, double* tau, double* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		double* work = new double[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		dormbr(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cunmbr( int block_size, char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, MKL_Complex8* a, int lda, MKL_Complex8* tau, MKL_Complex8* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		MKL_Complex8* work = new MKL_Complex8[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		cunmbr(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zunmbr( int block_size,  char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, MKL_Complex16* a, int lda, MKL_Complex16* tau, MKL_Complex16* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		MKL_Complex16* work = new MKL_Complex16[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		zunmbr(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cungbr( int block_size, char vect, int m, int n, int k, MKL_Complex8* a, int lda, MKL_Complex8* tau ){
		int info;
		int lwork = min(m,n)*block_size;
		MKL_Complex8* work = new MKL_Complex8[lwork];
		cungbr(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zungbr( int block_size, char vect, int m, int n, int k, MKL_Complex16* a, int lda, MKL_Complex16* tau ){
		int info;
		int lwork = min(m,n)*block_size;
		MKL_Complex16* work = new MKL_Complex16[lwork];
		zungbr(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_sorgbr( int block_size, char vect, int m, int n, int k, float* a, int lda, float* tau ){
		int info;
		int lwork = min(m,n)*block_size;
		float* work = new float[lwork];
		sorgbr(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dorgbr( int block_size, char vect, int m, int n, int k, double* a, int lda, double* tau ){
		int info;
		int lwork = min(m,n)*block_size;
		double* work = new double[lwork];
		dorgbr(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}
	
	int DLLEXPORT dna_lapack_sgebrd( int block_size,int m, int n, float* a, int lda, float* d, float* e, float* tauq, float* taup ){
		int info;
		int lwork = (m + n)*block_size;
		float* work = new float[lwork];
		sgebrd(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dgebrd( int block_size,int m, int n, double* a, int lda, double* d, double* e, double* tauq, double* taup ){
		int info;
		int lwork = (m + n)*block_size;
		double* work = new double[lwork];
		dgebrd(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cgebrd( int block_size,int m, int n, MKL_Complex8* a, int lda, float* d, float* e, MKL_Complex8* tauq, MKL_Complex8* taup ){
		int info;
		int lwork = (m + n)*block_size;
		MKL_Complex8* work = new MKL_Complex8[lwork];
		cgebrd(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zgebrd( int block_size,int m, int n, MKL_Complex16* a, int lda, double* d, double* e, MKL_Complex16* tauq, MKL_Complex16* taup ){
		int info;
		int lwork = (m + n)*block_size;
		MKL_Complex16* work = new MKL_Complex16[lwork];
		zgebrd(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_sgeqp3(int m, int n, float* a, int lda, int* jpvt, float* tau ){
		int info;
		int lwork = 3*n+1;
		float* work = new float[lwork];
		sgeqp3(&m, &n, a, &lda, jpvt, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dgeqp3(int m, int n, double* a, int lda, int* jpvt, double* tau ){
		int info;
		int lwork = 3*n+1;
		double* work = new double[lwork];
		dgeqp3(&m, &n, a, &lda, jpvt, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cgeqp3(int m, int n, MKL_Complex8* a, int lda, int* jpvt, MKL_Complex8* tau ){
		int info;
		int lwork = n+1;
		MKL_Complex8* work = new MKL_Complex8[lwork];
		float* rwork = new float[2*n];
		cgeqp3(&m, &n, a, &lda, jpvt, tau, work, &lwork, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}

	int DLLEXPORT dna_lapack_zgeqp3(int m, int n, MKL_Complex16* a, int lda, int* jpvt, MKL_Complex16* tau ){
		int info;
		int lwork = n+1;
		MKL_Complex16* work = new MKL_Complex16[lwork];
		double* rwork = new double[2*n];
		zgeqp3(&m, &n, a, &lda, jpvt, tau, work, &lwork, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}
	
	int DLLEXPORT dna_lapack_sormqr( int block_size,CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, float* a, int lda, float* tau, float* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		float* work = new float[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		sormqr(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}
	
	int DLLEXPORT dna_lapack_dormqr( int block_size,CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, double* a, int lda, double* tau, double* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		double* work = new double[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		dormqr(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cunmqr( int block_size,CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, MKL_Complex8* a, int lda, MKL_Complex8* tau, MKL_Complex8* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		MKL_Complex8* work = new MKL_Complex8[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		cunmqr(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zunmqr( int block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, MKL_Complex16* a, int lda, MKL_Complex16* tau, MKL_Complex16* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		MKL_Complex16* work = new MKL_Complex16[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		zunmqr(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_sorgqr( int block_size, int m, int n, int k, float* a, int lda, float* tau ){
		int info;
		int lwork = block_size*n;
		float* work = new float[lwork];
		sorgqr(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dorgqr(  int block_size, int m, int n, int k, double* a, int lda, double* tau ){
		int info;
		int lwork = block_size*n;
		double* work = new double[lwork];
		dorgqr(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cungqr(  int block_size, int m, int n, int k, MKL_Complex8* a, int lda, MKL_Complex8* tau ){
		int info;
		int lwork = block_size*n;
		MKL_Complex8* work = new MKL_Complex8[lwork];
		cungqr(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zungqr( int block_size, int m, int n, int k, MKL_Complex16* a, int lda, MKL_Complex16* tau ){
		int info;
		int lwork = block_size*n;
		MKL_Complex16* work = new MKL_Complex16[lwork];
		zungqr(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_sgetrs(const CBLAS_TRANSPOSE trans, int n, int nrhs, float* a, int lda, int* ipiv, float* b,int ldb ){
		int info;
		char tChar = getTchar(trans);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		sgetrs(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_dgetrs(const CBLAS_TRANSPOSE trans, int n, int nrhs, double* a, int lda, int* ipiv, double* b,int ldb ){
		int info;
		char tChar = getTchar(trans);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		dgetrs(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_cgetrs(const CBLAS_TRANSPOSE trans, int n, int nrhs, MKL_Complex8* a, int lda, int* ipiv, MKL_Complex8* b,int ldb ){
		int info;
		char tChar = getTchar(trans);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		cgetrs(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_zgetrs(const CBLAS_TRANSPOSE trans, int n, int nrhs, MKL_Complex16* a, int lda, int* ipiv, MKL_Complex16* b,int ldb ){
		int info;
		char tChar = getTchar(trans);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		zgetrs(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_sgesv(int n, int nrhs, float* a, int lda, int* ipiv, float* b, int ldb ){
		int info;
		sgesv(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_dgesv(int n, int nrhs, double* a, int lda, int* ipiv, double* b, int ldb ){
		int info;
		dgesv(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_cgesv(int n, int nrhs, MKL_Complex8* a, int lda, int* ipiv, MKL_Complex8* b, int ldb ){
		int info;
		cgesv(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_zgesv(int n, int nrhs, MKL_Complex16* a, int lda, int* ipiv, MKL_Complex16* b, int ldb ){
		int info;
		zgesv(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_sgetri(int block_size, int n, float* a, int lda, int* ipiv ){
		int info;
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
        int lwork = block_size*size;
        float* work = new float[lwork];
		sgetri(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_dgetri(int block_size, int n, double* a, int lda, int* ipiv ){
		int info;
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
        int lwork = block_size*size;
		double* work = new double[lwork];
		dgetri(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}
	
	int DLLEXPORT dna_lapack_cgetri(int block_size, int n, MKL_Complex8* a, int lda, int* ipiv ){
		int info;
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
        int lwork = block_size*size;
		MKL_Complex8* work = new MKL_Complex8[lwork];
		cgetri(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_zgetri(int block_size, int n, MKL_Complex16* a, int lda, int* ipiv ){
		int info;
		int size = max(1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
        int lwork = block_size*size;
		MKL_Complex16* work = new MKL_Complex16[lwork];
		zgetri(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_sgetrf(int m, int n, float* a, int lda, int *ipiv){
		int info;
		sgetrf(&m,&n,a,&lda,ipiv,&info);
		int size = max(1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_dgetrf(int m, int n, double *a, int lda, int *ipiv){
		int info;
		dgetrf(&m,&n,a,&lda,ipiv,&info);
		int size = max(1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}
	
	int DLLEXPORT dna_lapack_cgetrf(int m, int n, MKL_Complex8 *a, int lda, int *ipiv){
		int info;
		cgetrf(&m,&n,a,&lda,ipiv,&info);
		int size = max(1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}
	
	int DLLEXPORT dna_lapack_zgetrf(int m, int n, MKL_Complex16 *a, int lda, int *ipiv){
		int info;
		zgetrf(&m,&n,a,&lda,ipiv,&info);
		int size = max(1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	int DLLEXPORT dna_lapack_spotrf(const CBLAS_UPLO uplo, int n, float *a, int lda){
        int info;
        char uChar = getUchar(uplo);
        spotrf(&uChar, &n, a, &lda, &info);
        return info;
    }

	int DLLEXPORT dna_lapack_dpotrf(const CBLAS_UPLO uplo, int n, double *a, int lda) {
        int info;
        char uChar = getUchar(uplo);
        dpotrf(&uChar, &n, a, &lda, &info);
        return info;
	}

	int DLLEXPORT dna_lapack_cpotrf(const CBLAS_UPLO uplo, int n, MKL_Complex8 *a, int lda) {
        int info;
        char uChar = getUchar(uplo);
        cpotrf(&uChar, &n, a, &lda, &info);
        return info;
	}

	int DLLEXPORT dna_lapack_zpotrf(const CBLAS_UPLO uplo, int n, MKL_Complex16 *a, int lda) {
        int info;
        char uChar = getUchar(uplo);
        zpotrf(&uChar, &n, a, &lda, &info);
        return info;
	}

	int DLLEXPORT dna_lapack_spotrs(const CBLAS_UPLO uplo, int n, int nrhs, float *a, int lda, float *b, int ldb) {
        int info;
        char uChar = getUchar(uplo);
        spotrs(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	int DLLEXPORT dna_lapack_dpotrs(const CBLAS_UPLO uplo, int n, int nrhs, double *a, int lda, double *b, int ldb) {
        int info;
        char uChar = getUchar(uplo);
        dpotrs(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	int DLLEXPORT dna_lapack_cpotrs(const CBLAS_UPLO uplo, int n, int nrhs, MKL_Complex8 *a, int lda, MKL_Complex8 *b, int ldb) {
        int info;
        char uChar = getUchar(uplo);
        cpotrs(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	int DLLEXPORT dna_lapack_zpotrs(const CBLAS_UPLO uplo, int n, int nrhs, MKL_Complex16 *a, int lda, MKL_Complex16 *b, int ldb) {
        int info;
        char uChar = getUchar(uplo);
        zpotrs(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	int DLLEXPORT dna_lapack_spocon(const CBLAS_UPLO uplo, int n, float *a, int lda, float anorm, float *rcond) {
		int info;
		float* work = new float[3*n];
		int* iwork = new int[n];
		char uChar = getUchar(uplo);
		spocon(&uChar, &n, a, &lda, &anorm, rcond, work, iwork, &info);
		delete[] work;
		delete[] iwork;
		return info;
	}

	int DLLEXPORT dna_lapack_dpocon(const CBLAS_UPLO uplo, int n, double *a, int lda, double anorm, double *rcond) {
		int info;
		double* work = new double[3*n];
		int* iwork = new int[n];
		char uChar = getUchar(uplo);
		dpocon(&uChar, &n, a, &lda, &anorm, rcond, work, iwork, &info);
		delete[] work;
		delete[] iwork;
		return info;
	}

	int DLLEXPORT dna_lapack_cpocon(const CBLAS_UPLO uplo, int n, MKL_Complex8 *a, int lda, float anorm, float *rcond) {
		int info;
		MKL_Complex8* work = new MKL_Complex8[2*n];
		float* rwork = new float[n];
		char uChar = getUchar(uplo);
		cpocon(&uChar, &n, a, &lda, &anorm, rcond, work, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}

	int DLLEXPORT dna_lapack_zpocon(const CBLAS_UPLO uplo, int n, MKL_Complex16 *a, int lda, double anorm, double *rcond) {
		int info;
		MKL_Complex16* work = new MKL_Complex16[2*n];
		double* rwork = new double[n];
		char uChar = getUchar(uplo);
		zpocon(&uChar, &n, a, &lda, &anorm, rcond, work, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}

	int DLLEXPORT dna_lapack_spotri(const CBLAS_UPLO uplo, int n, float *a, int lda) {
		int info;
		char uChar = getUchar(uplo);
		spotri(&uChar, &n, a, &lda, &info);
		return info;
	}

	int DLLEXPORT dna_lapack_dpotri(const CBLAS_UPLO uplo, int n, double *a, int lda) {
		int info;
		char uChar = getUchar(uplo);
		dpotri(&uChar, &n, a, &lda, &info);
		return info;
	}

	int DLLEXPORT dna_lapack_cpotri(const CBLAS_UPLO uplo, int n, MKL_Complex8 *a, int lda) {
		int info;
		char uChar = getUchar(uplo);
		cpotri(&uChar, &n, a, &lda, &info);
		return info;
	}

	int DLLEXPORT dna_lapack_zpotri(const CBLAS_UPLO uplo, int n, MKL_Complex16 *a, int lda) {
		int info;
		char uChar = getUchar(uplo);
		zpotri(&uChar, &n, a, &lda, &info);
		return info;
	}

	int DLLEXPORT dna_lapack_sgehrd(int block_size, int n, int ilo, int ihi, float *a, int lda, float *tau) {
		int info;
		int lwork = block_size*n;
		float* work = new float[lwork];
		sgehrd(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dgehrd(int block_size, int n, int ilo, int ihi, double *a, int lda, double *tau) {
		int info;
		int lwork = block_size*n;
		double* work = new double[lwork];
		dgehrd(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cgehrd(int block_size, int n, int ilo, int ihi, MKL_Complex8 *a, int lda, MKL_Complex8 *tau) {
		int info;
		int lwork = block_size*n;
		MKL_Complex8* work = new MKL_Complex8[lwork];
		cgehrd(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zgehrd(int block_size, int n, int ilo, int ihi, MKL_Complex16 *a, int lda, MKL_Complex16 *tau) {
		int info;
		int lwork = block_size*n;
		MKL_Complex16* work = new MKL_Complex16[lwork];
		zgehrd(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_sorghr(int block_size, int n, int ilo, int ihi, float *a, int lda, float *tau) {
		int info;
		int lwork = max(ihi-ilo,1)*block_size;
		float* work = new float[lwork];
		sorghr(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dorghr(int block_size, int n, int ilo, int ihi, double *a, int lda, double *tau) {
		int info;
		int lwork = max(ihi-ilo,1)*block_size;
		double* work = new double[lwork];
		dorghr(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cunghr(int block_size, int n, int ilo, int ihi, MKL_Complex8 *a, int lda, MKL_Complex8 *tau){
		int info;
		int lwork = max(ihi-ilo,1)*block_size;
		MKL_Complex8* work = new MKL_Complex8[lwork];
		cunghr(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zunghr(int block_size, int n, int ilo, int ihi, MKL_Complex16 *a, int lda, MKL_Complex16 *tau){
		int info;
		int lwork = max(ihi-ilo,1)*block_size;
		MKL_Complex16* work = new MKL_Complex16[lwork];
		zunghr(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_sormhr(int block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, int ilo, int ihi, float* a, int lda, float* tau, float* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		float* work = new float[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		sormhr(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dormhr(int block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, int ilo, int ihi, double* a, int lda, double* tau, double* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		double* work = new double[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		dormhr(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cunmhr(int block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, int ilo, int ihi, MKL_Complex8* a, int lda, MKL_Complex8* tau, MKL_Complex8* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		MKL_Complex8* work = new MKL_Complex8[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		cunmhr(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zunmhr(int block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, int m, int n, int k, int ilo, int ihi, MKL_Complex16* a, int lda, MKL_Complex16* tau, MKL_Complex16* c, int ldc ){
		int info;
		int lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		MKL_Complex16* work = new MKL_Complex16[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		zunmhr(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

    int DLLEXPORT dna_lapack_sbdsqr(CBLAS_UPLO uplo, int n, int ncvt, int nru, int ncc, float* d, float* e, float* vt, int ldvt, float* u, int ldu, float* c, int ldc ){
        int info;
        int lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max(1,2*n);
        }else{
            lwork = max(1,4*(n-1));
        }

        float* work = new float[lwork];
        char uChar = getUchar(uplo);
        sbdsqr(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    int DLLEXPORT dna_lapack_dbdsqr(CBLAS_UPLO uplo, int n, int ncvt, int nru, int ncc, double* d, double* e, double* vt, int ldvt, double* u, int ldu, double* c, int ldc ){
        int info;
        int lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max(1,2*n);
        }else{
            lwork = max(1,4*(n-1));
        }

        double* work = new double[lwork];
        char uChar = getUchar(uplo);
        dbdsqr(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    int DLLEXPORT dna_lapack_cbdsqr(CBLAS_UPLO uplo, int n, int ncvt, int nru, int ncc, float* d, float* e, MKL_Complex8* vt, int ldvt, MKL_Complex8* u, int ldu, MKL_Complex8* c, int ldc ){
        int info;
        int lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max(1,2*n);
        }else{
            lwork = max(1,4*(n-1));
        }

        float* work = new float[lwork];
        char uChar = getUchar(uplo);
        cbdsqr(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    int DLLEXPORT dna_lapack_zbdsqr(CBLAS_UPLO uplo, int n, int ncvt, int nru, int ncc, double* d, double* e, MKL_Complex16* vt, int ldvt, MKL_Complex16* u, int ldu, MKL_Complex16* c, int ldc ){
        int info;
        int lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max(1,2*n);
        }else{
            lwork = max(1,4*(n-1));
        }

        double* work = new double[lwork];
        char uChar = getUchar(uplo);
        zbdsqr(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    int DLLEXPORT dna_lapack_sgesvd(int m, int n, float* a, int lda, float* s, float* u, int ldu, float* vt, int ldvt ){
        int info;
        int lwork = max(3*min(m,n)+max(m,n), 5*min(m,n));
        float* work = new float[lwork];
        char S = 'S';
		char A = 'A';
        sgesvd( &A, &A, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info );
        delete[] work;
        return info;
    }

    int DLLEXPORT dna_lapack_dgesvd(int m, int n, double* a, int lda, double* s, double* u, int ldu, double* vt, int ldvt ){
        int info;
        int lwork = max(3*min(m,n)+max(m,n), 5*min(m,n));
        double* work = new double[lwork];
        char S = 'S';
		char A = 'A';
        dgesvd( &A, &A, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info );
        delete[] work;
        return info;
    }

    int DLLEXPORT dna_lapack_cgesvd(int m, int n, MKL_Complex8* a, int lda, float* s, MKL_Complex8* u, int ldu, MKL_Complex8* vt, int ldvt ){
        int info;
        int lwork = 2*min(m,n)+max(m,n);
        float* rwork = new float[max(1, 5*min(m,n))];
        MKL_Complex8* work = new MKL_Complex8[lwork];
        char S = 'S';
		char A = 'A';
        cgesvd( &A, &A, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, rwork, &info );
        delete[] work;
		delete[] rwork;
        return info;
    }

    int DLLEXPORT dna_lapack_zgesvd(int m, int n, MKL_Complex16* a, int lda, double* s, MKL_Complex16* u, int ldu, MKL_Complex16* vt, int ldvt ){
        int info;
        int lwork = 2*min(m,n)+max(m,n);
        double* rwork = new double[max(1, 5*min(m,n))];
        MKL_Complex16* work = new MKL_Complex16[lwork];
        char S = 'S';
		char A = 'A';
        zgesvd( &A, &A, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, rwork, &info );
        delete[] work;
		delete[] rwork;
        return info;
    }

	int DLLEXPORT dna_lapack_sgeqrf(int block_size, int m, int n, float *a, int lda, float *tau) {
		int info;
		int lwork = max(1,block_size*n);
		float *work = new float[lwork];
		sgeqrf(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_dgeqrf(int block_size, int m, int n, double *a, int lda, double *tau) {
		int info;
		int lwork = max(1,block_size*n);
		double *work = new double[lwork];
		dgeqrf(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_cgeqrf(int block_size, int m, int n, MKL_Complex8 *a, int lda, MKL_Complex8 *tau) {
		int info;
		int lwork = max(1,block_size*n);
		MKL_Complex8 *work = new MKL_Complex8[lwork];
		cgeqrf(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	int DLLEXPORT dna_lapack_zgeqrf(int block_size, int m, int n, MKL_Complex16 *a, int lda, MKL_Complex16 *tau) {
		int info;
		int lwork = max(1,block_size*n);
		MKL_Complex16 *work = new MKL_Complex16[lwork];
		zgeqrf(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

}
